package rest

import (
	"errors"
	"gitee.com/yysf-xin/dproxy/pkg/app"
	"github.com/go-chi/chi/v5"
	"gorm.io/gorm"
	"net/http"
	"reflect"
	"strconv"
)

const (
	LIST = 1 << iota
	GET
	NEW
	UPDATE
	DELETE
)

type Handler interface {

}

type Operate struct {

}
type Api struct {
	BaseUrl string
	Db      *gorm.DB
	Model   app.Modeler
	Router  chi.Router
	ty      reflect.Type
	arrType reflect.Type
}

// Customer 自定义重写rest方法
type Customer interface {
	CustomFlag() uint8
}

func (h *Api) Create() interface{} {
	return reflect.New(h.ty).Interface()
}

func NewRestApi(m app.Modeler) (r *Api) {
	r = &Api{
		BaseUrl: "/" + m.TableName(),
		Model:   m,
		ty:      reflect.TypeOf(m).Elem(),
		arrType: reflect.SliceOf(reflect.TypeOf(m)),
	}
	return r
}

func (h *Api) InitRoute(route chi.Router) {
	route.Route(h.BaseUrl, func(r chi.Router) {
		h.Router = r

		var flag uint8 = 0
		if c, ok := h.Model.(Customer); ok {
			flag = c.CustomFlag()
		}

		if flag&LIST == 0 {
			r.Get("/", app.Json(nil, h.List))
		}
		if flag&GET == 0 {
			r.Get("/{id}", app.JsonHttp(nil, h.ById))
		}
		if flag&NEW == 0 {
			r.Post("/", app.Json(h.Create, h.New))
		}
		if flag&UPDATE == 0 {
			r.Put("/{id}", app.Json(h.Create, h.Update))
		}
		if flag&DELETE == 0 {
			r.Delete("/{id}", app.JsonHttp(nil, h.Delete))
		}
	})
}

func (h *Api) List(interface{}) (res interface{}, err error) {
	slice := reflect.MakeSlice(h.arrType, 0, 10).Interface()
	//x := reflect.New(slice.Type())
	//x.Elem().Set(slice)
	err = h.Db.Find(&slice).Error
	if err == nil {
		res = &slice
	}
	return
}

func (h *Api) ById(_ http.ResponseWriter, r *http.Request, _ interface{}) (res interface{}, err error) {
	id := chi.URLParam(r, "id")
	res = h.Create()
	err = h.Db.First(res, id).Error
	if err != nil {
		res = nil
	}
	return
}

func (h *Api) New(req interface{}) (res interface{}, err error) {
	err = h.Db.Create(req).Error
	if err == nil {
		res = req
	}
	return
}

func (h *Api) Update(req interface{}) (res interface{}, err error) {
	if m, ok := req.(app.Modeler); ok {
		if m.GetId() == 0 {
			return nil, errors.New("id is null")
		}
		if err = h.Db.Updates(m).Error; err == nil {
			err = h.Db.First(req, m.GetId()).Error
		}
	} else {
		err = errors.New("error type " + reflect.TypeOf(req).Kind().String())
	}
	if err == nil {
		res = req
	} else {
		res = nil
	}
	return
}

func (h *Api) Delete(writer http.ResponseWriter, r *http.Request, i interface{}) (rs interface{}, err error) {
	id := chi.URLParam(r, "id")
	err = h.Db.Delete(&h.Model, id).Error
	return
}

func PathParamId(r *http.Request) (i uint, err error) {
	id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
	if err != nil {
		return
	}
	i = uint(id)
	return
}
func QueryParamId(r *http.Request,key string) (i uint, err error) {
	id, err := strconv.ParseUint(r.URL.Query().Get(key), 10, 64)
	if err != nil {
		return
	}
	i = uint(id)
	return
}

func FindModelByReq(r *http.Request, dest interface{}, db *gorm.DB) (err error) {
	id, err := PathParamId(r)
	if err != nil {
		return
	}
	err = db.First(dest, id).Error
	return
}
